/*
 * Copyright (c) 2008-2014, RF-Embedded GmbH
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without modification, 
 * are permitted provided that the following conditions are met:
 * 
 *  1. Redistributions of source code must retain the above copyright notice, 
 *     this list of conditions and the following disclaimer.
 *  2. Redistributions in binary form must reproduce the above copyright notice, 
 *     this list of conditions and the following disclaimer in the 
 *     documentation and/or other materials provided with the distribution.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
 * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 
 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package com.rfe.protocol;

import com.rfe.helper.JrfeHelper;

/**
 * Exception class that is thrown from the protocol handler
 */
public class JrfeProtocolException extends Exception {

	/**
	 * Generated serial id
	 */
	private static final long serialVersionUID = 4436071492769041454L;

	/**
	 * The possible error types
	 */
	public enum ErrorType {
		/** The given data is not valid */
		DATA_INPUT_ERROR,
		/** The command could not be sent */
		SEND_ERROR,
		/** There was no answer received from the reader */
		RECEIVE_ERROR,
		/** The reader sent an error as response */
		ERROR_RECEIVED,
		/** The data in the response of the reader is not valid */
		DATA_ERROR,
	}
	
	/** The error type */
	public ErrorType m_errorType;
	
	/** The name of the variable */
	public String m_name;

	/** The sent data */
	public byte[] m_sentData = null;
	
	/** The received data */
	public byte[] m_receivedData = null;
	
	/** The received error */
	public int m_receivedError = 0;
	
	/**
	 * Constructor is private to protect instantiation without using the static functions
	 */
	private JrfeProtocolException()
	{
	}
	
	/**
	 * Creates a new exception with a DATA_INPUT_ERROR
	 * @param name		The name of the variable
	 * @return			The new exception
	 */
	public static JrfeProtocolException DataInputError(String name)
	{
		JrfeProtocolException e = new JrfeProtocolException();
		e.m_name = new String(name);
		e.m_errorType = ErrorType.DATA_INPUT_ERROR;
		
		return e;
	}
	
	/**
	 * Creates a new exception with a SEND_ERROR
	 * @param sentData		The sent data
	 * @return				The new exception
	 */
	public static JrfeProtocolException SendError(byte[] sentData)
	{
		JrfeProtocolException e = new JrfeProtocolException();
		e.m_sentData = new byte[sentData.length];
		System.arraycopy(sentData, 0, e.m_sentData, 0, e.m_sentData.length);
		
		e.m_errorType = ErrorType.SEND_ERROR;
		
		return e;
	}
	
	/**
	 * Creates a new exception with a RECEIVE_ERROR
	 * @param sentData		The sent data
	 * @return				The new exception
	 */
	public static JrfeProtocolException ReceiveError(byte[] sentData)
	{
		JrfeProtocolException e = new JrfeProtocolException();
		e.m_sentData = new byte[sentData.length];
		System.arraycopy(sentData, 0, e.m_sentData, 0, e.m_sentData.length);
		
		e.m_errorType = ErrorType.RECEIVE_ERROR;
		
		return e;
	}
	
	/**
	 * Creates a new exception with an ERROR_RECEIVED 
	 * @param sentData		The sent data
	 * @param recvdData		The received data
	 * @param recvdError	The received error
	 * @return				The new exception
	 */
	public static JrfeProtocolException ErrorReceived(byte[] sentData, byte[] recvdData, int recvdError)
	{
		JrfeProtocolException e = new JrfeProtocolException();
		e.m_sentData = new byte[sentData.length];
		System.arraycopy(sentData, 0, e.m_sentData, 0, e.m_sentData.length);

		e.m_receivedData = new byte[recvdData.length];
		System.arraycopy(recvdData, 0, e.m_receivedData, 0, e.m_receivedData.length);
		
		e.m_receivedError = recvdError;

		e.m_errorType = ErrorType.ERROR_RECEIVED;
		
		return e;
	}
	
	/**
	 * Creates a new exception with a DATA_ERROR
	 * @param sentData		The sent data
	 * @param recvdData		The received data
	 * @return				The new exception
	 */
	public static JrfeProtocolException DataError(byte[] sentData, byte[] recvdData)
	{
		JrfeProtocolException e = new JrfeProtocolException();
		e.m_sentData = new byte[sentData.length];
		System.arraycopy(sentData, 0, e.m_sentData, 0, e.m_sentData.length);

		e.m_receivedData = new byte[recvdData.length];
		System.arraycopy(recvdData, 0, e.m_receivedData, 0, e.m_receivedData.length);

		e.m_errorType = ErrorType.DATA_ERROR;
		
		return e;
	}
	
	
	/**
	 * Returns the error type
	 * @return	The error type
	 */
	public ErrorType errorType()
	{
		return m_errorType;
	}
	
	/**
	 * Returns the name of the variable
	 * @return	The name
	 */
	public String name()
	{
		return m_name;
	}
	
	/**
	 * Returns the sent data
	 * @return	The sent data
	 */
	public byte[] sentData()
	{
		return m_sentData;
	}
	
	/**
	 * Returns the received data
	 * @return	The received data
	 */
	public byte[] receivedData()
	{
		return m_receivedData;
	}
	
	/**
	 * Returns the received error
	 * @return	The received error
	 */
	public int receivedError()
	{
		return m_receivedError;
	}
	
	/**
	 * Converts the data of the exception to a string.
	 */
	public String toString()
	{
		StringBuilder strBld = new StringBuilder();
		
		switch(m_errorType)
		{
		case DATA_INPUT_ERROR:
			strBld.append("DATA INPUT\n");
			strBld.append("  Invalid Data:  " + m_name + "\n");
			break;
		case SEND_ERROR:
			strBld.append("SEND ERROR\n");
			strBld.append("  Data Sent:  " + JrfeHelper.toHexString(m_sentData) + "\n");
			break;
		case RECEIVE_ERROR:
			strBld.append("RECEIVE ERROR\n");
			strBld.append("  Data Sent:  " + JrfeHelper.toHexString(m_sentData) + "\n");
			break;
		case ERROR_RECEIVED:
			strBld.append("ERROR RECEIVED\n");
			strBld.append("  Data Sent:  " + JrfeHelper.toHexString(m_sentData) + "\n");
			strBld.append("  Data Rcvd:  " + JrfeHelper.toHexString(m_receivedData) + "\n");
			strBld.append("  Error Rcvd: " + JrfeHelper.toHexString((byte)m_receivedError) + " = " + JrfeConstants.eRFE_RET_VALUE.toString(m_receivedError) + "\n");
			break;
		case DATA_ERROR:
			strBld.append("DATA ERROR\n");
			strBld.append("  Data Sent:  " + JrfeHelper.toHexString(m_sentData) + "\n");
			strBld.append("  Data Rcvd:  " + JrfeHelper.toHexString(m_receivedData) + "\n");
		}
		
		return strBld.toString();
	}
}


